package com.dinzeer.sjapadder.sa;

import com.dinzeer.legendreliclib.lib.util.slashblade.SlashBladeUtil;
import com.dinzeer.sjapadder.register.SjaSpecialEffectRegsitry;
import com.dinzeer.sjapadder.se.ShadowOfRevenant;
import mods.flammpfeil.slashblade.capability.slashblade.ISlashBladeState;
import mods.flammpfeil.slashblade.data.tag.SlashBladeEntityTypeTagProvider;
import mods.flammpfeil.slashblade.item.ItemSlashBlade;
import mods.flammpfeil.slashblade.registry.SpecialEffectsRegistry;
import mods.flammpfeil.slashblade.registry.specialeffects.SpecialEffect;
import mods.flammpfeil.slashblade.util.AttackManager;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.DustParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.AABB;

import java.util.List;
import java.util.function.Predicate;

import static com.dinzeer.sjapadder.Config.*;

public class ExplosiveDawn {

    protected static int RADIUS_SMALL = 2;

    protected static AABB getAreaSmall(BlockPos blockPos) {
        return new AABB(
                blockPos.offset(-RADIUS_SMALL, -RADIUS_SMALL, -RADIUS_SMALL),
                blockPos.offset(RADIUS_SMALL, RADIUS_SMALL, RADIUS_SMALL)
        );
    }

    protected static int RADIUS_LARGE = 8;

    protected static AABB getAreaLarge(BlockPos blockPos) {
        return new AABB(
                blockPos.offset(-RADIUS_LARGE, -RADIUS_LARGE, -RADIUS_LARGE),
                blockPos.offset(RADIUS_LARGE, RADIUS_LARGE, RADIUS_LARGE)
        );
    }

    protected static final Predicate<LivingEntity> VALID_ENTITY = entity -> {
        return !entity.getType().is(SlashBladeEntityTypeTagProvider.EntityTypeTags.ATTACKABLE_BLACKLIST);
    };

    public static final DustParticleOptions PARTICLE_RED = new DustParticleOptions(ShadowOfRevenant.COLOR_RED, 2.0F);

    public static void doExplosiveDawn(LivingEntity attacker) {
        if (attacker.level() instanceof ServerLevel serverLevel) {
            ItemStack bladeStack = attacker.getMainHandItem();
            if (bladeStack.getItem() instanceof ItemSlashBlade) {
                ISlashBladeState state = SlashBladeUtil.getState(bladeStack);
                List<ResourceLocation> effects = state.getSpecialEffects();

                boolean hasRevenantSE = false;

                for (ResourceLocation effectId : effects) {
                    SpecialEffect effect = SpecialEffectsRegistry.REGISTRY.get().getValue(effectId);
                    if (effect instanceof ShadowOfRevenant) {
                        hasRevenantSE = true;
                        break;

                    }
                }
                Entity mainTarget = state.getTargetEntity(serverLevel);
                if (mainTarget == null) mainTarget = attacker;

                doExplosion(serverLevel, attacker, state, mainTarget.getOnPos().above(), hasRevenantSE);

                if (hasRevenantSE) {
                    CompoundTag nbt = bladeStack.getOrCreateTag();
                    if (!nbt.contains(ShadowOfRevenant.SHADOW_OF_REVENANT)) {
                        nbt.put(ShadowOfRevenant.SHADOW_OF_REVENANT, new CompoundTag());
                    }
                    CompoundTag shadowOfRevenantTag = nbt.getCompound(ShadowOfRevenant.SHADOW_OF_REVENANT);
                    for (int i = 0; i < 3; i++) {
                        shadowOfRevenantTag.putInt(ShadowOfRevenant.REVENANT_KEYS[i], 5);
                    }
                }

            }
        }
    }

    public static void doPreExplosiveDawn(LivingEntity attacker) {
        attacker.playSound(SoundEvents.AMETHYST_BLOCK_PLACE, 10.0f, 0.5f);
        attacker.playSound(SoundEvents.AMETHYST_BLOCK_FALL, 5.0f, 2.0f);
        attacker.playSound(SoundEvents.AMETHYST_BLOCK_RESONATE, 3.0f, 1.0f);

    }

    public static void doExplosion(ServerLevel level, LivingEntity attacker, ISlashBladeState state, BlockPos targetPos, boolean hasRevenantSE) {
        List<LivingEntity> listSmall = level.getEntitiesOfClass(LivingEntity.class, getAreaSmall(targetPos), VALID_ENTITY);
        int damageCounts = Math.min(4, listSmall.size());

        for (LivingEntity target : listSmall) {
            if (target == attacker) continue;
            doExplosionAttack(level, attacker, target, damageCounts,
                    explosiveDawnBigExplosionRatio, hasRevenantSE);
            target.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 10, 5));
        }

        level.explode(attacker,
                targetPos.getX(), targetPos.getY(), targetPos.getZ(),
                3.0f,
                Level.ExplosionInteraction.NONE);

        if (attacker instanceof ServerPlayer player) {
            if (SpecialEffect.isEffective(SjaSpecialEffectRegsitry.SHADOW_OF_REVENANT.get(), player.experienceLevel)) {
                List<LivingEntity> listLarge = level.getEntitiesOfClass(LivingEntity.class, getAreaLarge(targetPos), VALID_ENTITY);
                for (LivingEntity target : listLarge) {
                    if (target == attacker) continue;
                    doExplosionAttack(level, attacker, target, damageCounts,
                            explosiveDawnSmallExplosionRatio, hasRevenantSE);
                    target.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 5, 1));
                }
            }
        }
    }


    private static void doExplosionAttack(ServerLevel level, LivingEntity attacker, LivingEntity target,
                                          int damageCounts, float ratio, boolean hasRevenantSE) {
        for (int i = 0; i < damageCounts; i++) {
            doExplosionParticles(level, target.getOnPos().above(), hasRevenantSE);
            AttackManager.doMeleeAttack(attacker, target, true, false,
                    explosiveDawnMainRatio * ratio);
        }

    }

    private static void doExplosionParticles(ServerLevel level, BlockPos pos, boolean hasRevenantSE) {
        level.sendParticles(
                ParticleTypes.EXPLOSION,
                pos.getX() + 0.5d,
                pos.getY() + 0.5d,
                pos.getZ() + 0.5d,
                1,
                0.5d, 0.5d, 0.5d,
                0.125d
        );
        if (hasRevenantSE) {
            level.sendParticles(
                    ParticleTypes.EXPLOSION,
                    pos.getX() + 0.5d,
                    pos.getY() + 0.5d,
                    pos.getZ() + 0.5d,
                    1,
                    1.0d, 1.0d, 1.0d,
                    0.25d
            );
            level.sendParticles(
                    PARTICLE_RED,
                    pos.getX() + 0.5d,
                    pos.getY() + 0.5d,
                    pos.getZ() + 0.5d,
                    12,
                    2.0d, 2.0d, 2.0d,
                    0.1d
            );

        }

    }
}
